from pypylon import pylon
from pypylon import genicam
import numpy as np
import threading
import multiprocessing
from imageProcess import boldProcess
from PyQt5.QtCore import QRunnable, QThreadPool,pyqtSlot,QObject,pyqtSignal


namesCamsToUse = {0: 'acA2040-25gmNIR'}
countOfImagesToGrab = 10
alldark = []
from PyQt5 import QtCore
lock = threading.Lock()

# class SendImage(QRunnable):
#     def __init__(self, image):
#         super().__init__()
#         self.image = image
#     @pyqtSlot()
#     def run(self):

class ImageArrived(QObject):
    imageArrived = pyqtSignal(np.ndarray)

class ImageSend(QRunnable):
    def __init__(self, image):
        super().__init__()
        self.image = image
        self.signal = ImageArrived()

    @pyqtSlot()
    def run(self):
        self.signal.imageArrived.emit(self.image)



# class BaslerCam(pylon.ImageEventHandler):
class BaslerCam(QtCore.QObject, pylon.ImageEventHandler):
    #定义了信号
    imageArrived = QtCore.pyqtSignal(np.ndarray)
    def __init__(self):
        super().__init__()
        self.num = 1
        self.alldark = []


        #得到传输层的实例
        self.tlFactory = pylon.TlFactory.GetInstance()
        print('*', self.tlFactory)

        #得到所有的连接的设备，没有设备就退出
        self.devices = self.tlFactory.EnumerateDevices()
        print('**', self.devices)
        if len(self.devices) == 0:
            raise pylon.RuntimeException("No camera present.")

        #为吵到的设备创建一组相机实例
        self.cameras = pylon.InstantCameraArray(len(self.devices))
        self.camList = []

    def openCommunications(self, camToUse):
        print(camToUse)
        self.camNames = camToUse
        for i, cam in enumerate(self.cameras):
            try:
                cam.Attach(self.tlFactory.CreateDevice(self.devices[i]))
                cam.Open()
                self.removeTargetgrayLimit(cam)    #消除自动模式下的目标灰度限制
                cam.AutoFunctionProfile.SetValue('ExposureMinimum')
                print('相机打开了')

                if cam.DeviceModelName() not in self.camNames.values():
                    cam.Close()
                else:
                    camContext = self.setCamContextByKey(cam.DeviceModelName())
                    cam.SetCameraContext(camContext)
                    cam.RegisterImageEventHandler(self, pylon.RegistrationMode_Append, pylon.Cleanup_Delete)
                    print('打开获取')
                    self.camList.append(i)

            except genicam._genicam.RuntimeException:
                self.cameras.DetachDevice()
                self.cameras.DestroyDevice()

    def setCamContextByKey(self, deviceID):
        for key, value in self.camNames.items():
            if value == deviceID:
                return key

    def returnCamList(self):
        camList = []
        for i, cam in enumerate(self.cameras):
            try:
                cam.Attach(self.tlFactory.CreateDevice(self.devices[i]))
                cam.Open()
                camList.append(str(cam.DeviceModelName()))
            except genicam._genicam.RuntimeException:
                self.cameras.DetachDevice()
                self.cameras.DestroyDevice()
        return camList

    def returnExposureTimeRange(self):
        for i in self.camList:
            cam = self.cameras[i]
            min = cam.ExposureTimeRaw.Min
            max = cam.ExposureTimeRaw.Max
            return min,max

    def returnGainRange(self):
        for i in self.camList:
            cam = self.cameras[i]
            min = cam.GainRaw.Min
            max = cam.GainRaw.Max
            return min,max

    def setExposure(self, value):
        for i in self.camList:
            cam = self.cameras[i]
            cam.ExposureTimeRaw.SetValue(value)
            print('设置得值为：%i' %value)


    def setGain(self, value):
        for i in self.camList:
            cam = self.cameras[i]
            # cam.GainAuto.SetValue(GainAuto_Off)
            # cam.GainSelector.SetValue(GainSelector_All)
            cam.GainRaw.Value = value

    def getGain(self):
        for i in self.camList:
            cam = self.cameras[i]
            return cam.GainRaw.GetValue()

    def autoExposure(self, state):
        for i in self.camList:
            cam = self.cameras[i]
            if state:
                cam.ExposureAuto = 'Continuous'
                print('自动曝光开启')
            else:
                cam.ExposureAuto.SetValue('Off')
                print('自动曝光关闭')

    def autoGain(self, state):
        for i in self.camList:
            cam = self.cameras[i]
            if state:
                cam.GainAuto.SetValue('Continuous')
                print('自动增益开启')
            else:
                cam.GainAuto.SetValue('Off')
                print('自动增益关闭')

    def grabdark(self):
        for i in self.camList:
            cam = self.cameras[i]
            try:
                # Start the grabbing of c_countOfImagesToGrab images.
                # The camera device is parameterized with a default configuration which
                # sets up free-running continuous acquisition.
                cam.StartGrabbingMax(countOfImagesToGrab)

                # Camera.StopGrabbing() is called automatically by the RetrieveResult() method
                # when c_countOfImagesToGrab images have been retrieved.
                while cam.IsGrabbing():
                    # Wait for an image and then retrieve it. A timeout of 5000 ms is used.
                    grabResult = cam.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)

                    # Image grabbed successfully?
                    if grabResult.GrabSucceeded():
                        # Access the image data.
                        print("SizeX: ", grabResult.Width)
                        print("SizeY: ", grabResult.Height)
                        img = grabResult.Array
                        self.alldark.append(img)
                        print("Gray value of first pixel: ", img[0, 0])
                    else:
                        print("Error: ", grabResult.ErrorCode, grabResult.ErrorDescription)
                    grabResult.Release()
                self.alldark = np.stack(self.alldark, axis=0)
                self.alldark = np.median(self.alldark, axis=0)
                # plt.imshow(dark)
                # print(alldark.max(), alldark.min())
                print(self.alldark)
                return self.alldark


            except genicam.GenericException as e:
                # Error handling.
                print("An exception occurred.")
                print(e.GetDescription())

    def getPic(self):
        print('进入到触发')
        for i in self.camList:
            cam = self.cameras[i]
            cam.StartGrabbing(pylon.GrabStrategy_OneByOne, pylon.GrabLoop_ProvidedByInstantCamera)
            # cam.ExecuteSoftwareTrigger()

    def stopPic(self):
        print('关闭图像获取')
        for i in self.camList:
            cam = self.cameras[i]
            cam.StopGrabbing()

    def OnImagesSkipped(self, camera, countOfSkippedImages):
        print("OnImagesSkipped event for device ", camera.GetDeviceInfo().GetModelName())
        print(countOfSkippedImages, " images have been skipped.")





    def OnImageGrabbed(self, camera, grabResult):
        global alldark
        # print('进入到触发图片循环')
        if grabResult.GrabSucceeded():
            img = grabResult.GetArray()
            # centre = boldProcess.blodprocess(img)
            # mask = self.sector_mask(img.shape,(500,500),50,(0,360))
            # 1.使用try，except的模式,运行过程中会直接卡死
            # try:
            #     self.imageArrived.emit(img)   #单独使用的话，会在长时间跑程序中，突然一下子卡死，这个问题只能用线程解决,或者使用try，except解决
            # except:
            #     pass
            # else:
            #     print(threading.active_count())

            # 2.使用多线程
            try:
                t = threading.Thread(target=self.imageArrived.emit, args=(img,))
                t.start()
                print(threading.active_count())
            except:
                pass


            # 3.使用线程池,无法使用
            # try:
            #     task = self.executor.submit(traget=self.imageArrived.emit, args=(img,))
            #     print(task.done())
            # except:
            #     pass

            # 4.使用pyqt自带线程,无法使用
            # self.thread = SendImage(img)
            # self.thread.start()

            # 5.multiprocess进程也无法使用
            # p = multiprocessing.Process(target=self.imageArrived.emit, args=(img,))
            # p.start()

            # 6.使用pyqt的线程池进行传输
            # self.imageA = ImageSend(img)
            # self.threadpool.start(self.imageA)

        else:
            print("图片无法正确获取: ", grabResult.GetErrorCode(), grabResult.GetErrorDescription(), self.num)
            self.num += 1

    #####################################################
    #用于添加一个掩摸，到时候需要去除

    def img_mask(self,img):
        def sector_mask(shape, centre, radius, angle_range):
            """
            Return a boolean mask for a circular sector. The start/stop angles in
            `angle_range` should be given in clockwise order.
            """

            x, y = np.ogrid[:shape[0], :shape[1]]
            cx, cy = centre
            tmin, tmax = np.deg2rad(angle_range)

            # ensure stop angle > start angle
            if tmax < tmin:
                tmax += 2 * np.pi

            # convert cartesian --> polar coordinates
            r2 = (x - cx) * (x - cx) + (y - cy) * (y - cy)
            theta = np.arctan2(x - cx, y - cy) - tmin

            # wrap angles between 0 and 2*pi
            theta %= (2 * np.pi)

            # circular mask
            circmask = r2 <= radius * radius

            # angular mask
            anglemask = theta <= (tmax - tmin)

            return circmask * anglemask

        mask = sector_mask(img.shape, (200, 100),50,(0,360))
        mask1 = sector_mask(img.shape, (900, 100), 50, (0, 360))
        img[mask] = 254
        img[mask1] = 254
        return img

    ###############################################

    def setPixelFormat(self, pixelFormatName='Mono8'):
        for i in self.camList:
            cam = self.cameras[i]
            try:
                cam.PixelFormat = pixelFormatName
                print(cam.PixelFormat.GetValue())

            #这里待添加错误原因
            except genicam.GenericException as e:
                raise genicam.RuntimeException("无法应用配置. 错误为：%s" % e.GetDescription())

    def getWidthHeightMinMax(self):
        for i in self.camList:
            cam = self.cameras[i]
            widthMin = cam.Width.Min
            widthMax = cam.Width.Max
            heightMin = cam.Height.Min
            heightMax = cam.Height.Max
            return widthMin, widthMax, heightMin, heightMax

    def setCameraWidth(self, value):
        for i in self.camList:
            cam = self.cameras[i]
            cam.Width = value
            print('*',cam.Width.GetValue())

    def setCameraHeight(self, value):
        for i in self.camList:
            cam = self.cameras[i]
            cam.Height = value

    def setCameraXoffset(self, value):
        for i in self.camList:
            cam = self.cameras[i]
            cam.OffsetX = value

    def setCameraYoffset(self, value):
        for i in self.camList:
            cam = self.cameras[i]
            cam.OffsetY = value

    def setTargetgrayValue(self, value):
        for i in self.camList:
            cam = self.cameras[i]
            cam.AutoTargetValue.SetValue(value)


    def returnTargetgrayValueRange(self):
        for i in self.camList:
            cam = self.cameras[i]
            return cam.AutoTargetValue.Min, cam.AutoTargetValue.Max

    def returnPixelRange(self):
        for i in self.camList:
            cam = self.cameras[i]
            return cam.PixelDynamicRangeMin.GetValue(), cam.PixelDynamicRangeMax.GetValue()


    def removeTargetgrayLimit(self, cam):    #消除自动模式下的目标灰度限制
        cam.ParameterSelector.SetValue('AutoTargetValue')
        cam.RemoveLimits.SetValue(True)

    def getFrameRate(self):
        for i in self.camList:
            cam = self.cameras[i]
            return cam.ResultingFrameRateAbs.GetValue()

    def close(self):
        for i in self.camList:
            cam = self.cameras[i]
            cam.StopGrabbing()
            cam.Close()



def main():
    cams = BaslerCam()
    cams.openCommunications(namesCamsToUse)
    cams.autoExposure(True)
    cams.setPixelFormat()
    print(cams.getGain())

    print('***', cams.getFrameRate())
    cams.stopPic()



    # print(cams.returnCamList())
if __name__ == '__main__':
    main()